package ru.spbsu.electromenu.servlet;

import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.spbsu.electromenu.service.AbstractService;
import ru.spbsu.electromenu.util.StringUtils;
import ru.spbsu.electromenu.util.collections.Idable;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Date: 5/2/11
 * Time: 4:22 AM
 *
 * @author Artem Titov
 */
public class EditObjectServlet extends SpringHttpServlet {
    private static final Logger logger = LoggerFactory.getLogger(EditObjectServlet.class);

    protected <T extends Idable> T getObject(T object, HttpServletRequest request, AbstractService<T, ?> service) {
        final String sId = request.getParameter("id");
        int id = -1;
        try {
            id = Integer.parseInt(sId);
        } catch (Exception e) {
            // ignore
        }
        if (id > 0) {
            try {
                object = service.get(id);
            } catch (Exception e) {
                logger.error("Failed to load tag with id: {}", id, e);
            }
        }
        return object;
    }

    protected void parseObject(final HttpServletRequest request, Object object) throws UnsupportedEncodingException {
        final Method[] objectMethods = object.getClass().getDeclaredMethods();
        final List<Method> setters = new ArrayList<Method>();
        for (final Method method : objectMethods) {
            if (method.getName().startsWith("set")) {
                setters.add(method);
            }
        }
        for (final Method setter : setters) {
            final String fieldName = StringUtils.firstToLower(setter.getName().substring(3));
            try {
                final Field field = object.getClass().getDeclaredField(fieldName);
                if (field.getAnnotation(Unparsebale.class) != null) {
                    continue;
                }
                logger.debug("Getting field {}", fieldName);
                final String fieldValue = StringEscapeUtils.unescapeHtml(request.getParameter(fieldName));
                if (fieldValue == null) {
                    logger.debug("Field value is null");
                    if ("id".equals(fieldName)) {
                        continue;
                    }
                    logger.error("Necessary field {} missing", fieldName);
                    throw new IllegalArgumentException("Necessary field " + fieldName + " missing");
                }
                try {
                    logger.debug("Setting field to {} by invoking method {}", fieldValue, setter.getName());
                    logger.debug("Field class is " + field.getType());
                    if (int.class.equals(field.getType())) {
                        final int value = Integer.parseInt(fieldValue);
                        setter.invoke(object, value);
                    } else if (double.class.equals(field.getType())) {
                        final double value = Double.parseDouble(fieldValue);
                        setter.invoke(object, value);
                    } else if (boolean.class.equals(field.getType())) {
                        final boolean value = Boolean.parseBoolean(fieldValue);
                        setter.invoke(object, value);
                    } else if (String.class.equals(field.getType())) {
                        setter.invoke(object, fieldValue);
                    } else if (Date.class.equals(field.getType())) {
                        //todo parse date
                    }
                } catch (Exception e) {
                    logger.error("Failed to invoke setter method for field " + fieldName, e);
                    throw new IllegalArgumentException("Failed to set necessary field " + fieldName);
                }
            } catch (NoSuchFieldException e) {
                // ignore
            }
        }
    }

    protected <T extends Idable> void editObject(T object, HttpServletRequest request, AbstractService<T, ?> service) throws UnsupportedEncodingException {
        parseObject(request, object);
        logger.debug("Id: {}", object.getId());
        if (request.getParameter("save") != null) {
            if (object.getId() < 0) {
                service.put(object);
            } else {
                service.update(object);
            }
        } else if (request.getParameter("delete") != null) {
            service.delete(object.getId());
        }
    }
}
